use super::user::{SimpleUser, SimpleUserModel};
use chrono::{DateTime as CDateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use wither::{
    bson::{oid::ObjectId, DateTime},
    Model,
};

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum InviteTokenType {
    /// ## Immediate
    /// 立即加入型，无需提交哪些表单即可加入
    Immediate = 0,
    /// ## NeedToPost
    /// 需要提交完纳新表单才能加入
    NeedToPost = 1,
}
impl_into_bson!(InviteTokenType);
impl Default for InviteTokenType {
    fn default() -> Self {
        InviteTokenType::Immediate
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, Model)]
pub struct InviteTokenModel {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    pub club_id: ObjectId,
    pub creator: SimpleUserModel,
    /// 最多能用几次
    pub max_count: u64,
    pub use_count: u64,
    #[serde(default = "Vec::new")]
    pub checked_users: Vec<SimpleUserModel>,
    #[serde(rename = "type")]
    pub invite_type: InviteTokenType,
    pub created_time: DateTime,
    pub expired_time: DateTime,
    pub valid: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InviteTokenModelDTO {
    pub id: Option<String>,
    pub creator: SimpleUser,
    pub club_id: String,
    pub max_count: u64,
    pub use_count: u64,
    pub checked_users: Vec<SimpleUser>,
    #[serde(rename = "type")]
    pub invite_type: InviteTokenType,
    pub created_time: CDateTime<Utc>,
    pub expired_time: CDateTime<Utc>,
}

impl InviteTokenModel {
    pub fn new<
        C: Into<SimpleUserModel>,
        M: Into<u64>,
        T: Into<DateTime>,
        TY: Into<InviteTokenType>,
        CI: Into<ObjectId>,
    >(
        creator: C,
        max_count: M,
        expired_time: T,
        invite_type: TY,
        club_id: CI,
    ) -> Self {
        Self {
            id: None,
            creator: creator.into(),
            max_count: max_count.into(),
            use_count: 0,
            checked_users: vec![],
            created_time: DateTime::now(),
            expired_time: expired_time.into(),
            invite_type: invite_type.into(),
            club_id: club_id.into(),
            valid: true,
        }
    }
}

impl From<InviteTokenModel> for InviteTokenModelDTO {
    fn from(model: InviteTokenModel) -> Self {
        Self {
            id: model.id.map(|oid| oid.to_string()),
            creator: model.creator.into(),
            max_count: model.max_count,
            use_count: model.use_count,
            checked_users: model
                .checked_users
                .iter()
                .map(|s| s.clone().into())
                .collect(),
            created_time: model.created_time.to_chrono(),
            expired_time: model.expired_time.to_chrono(),
            invite_type: model.invite_type,
            club_id: model.club_id.to_string(),
        }
    }
}
